package com.huayi.datagovernance.utils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.huayi.datagovernance.common.SysConstant;
import com.huayi.datagovernance.entity.IscUserLocext;
import com.huayi.datagovernance.entity.UserOtherEntity;
import common.parent.system.tokenauth.DecodeTokenInfoDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Jwt工具类
 * @author wuch
 * @version 1.0
 * @date 2021/4/10 16:43
 */
@Slf4j
public class JwtUtils {

    //有效期  7天
    private static final  Long LIFE_TIME_SEVEN = new Long(86400L * 1000L * 7L);

    //颁发人
    private static final String ISSUER = "HUAYYI-SX-DATA-MANAGER";//华亿-山西-数据治理


    public static Long getLifeTimeSeven() {
        return LIFE_TIME_SEVEN;
    }

    /**
     *  生成token
     * @param user 登录用户
     * @return
     */
    public static final String createToken(IscUserLocext user){

        UserOtherEntity otherInfo =new UserOtherEntity();
        BeanUtils.copyProperties(user,otherInfo);
        HashMap<String, String> otherInfoMap = JSONObject.parseObject(JSONObject.toJSONString(otherInfo),
                new TypeReference<HashMap<String, String>>() {});
        return generateToken(user, new Date(),
                otherInfoMap,
                LIFE_TIME_SEVEN);
    }

    /**
     *  封装用户信息，调用工具生成token
     * @param user 用户
     * @param nowTime  当前时间
     * @param userOrgInfoLevelInfo  用户拓展信息
     * @param lifeTime 有效期
     * @return
     */
    private static String generateToken(IscUserLocext user, Date nowTime, HashMap<String, String> userOrgInfoLevelInfo, Long lifeTime) {
        return JWT.create()
                .withIssuer(ISSUER)
                .withIssuedAt(nowTime)
                .withExpiresAt(new Date(nowTime.getTime()+ lifeTime))
                .withAudience(user.getIscId())
                .withClaim("userId",user.getIscId())
                .withClaim("userName",user.getRymc())
                .withClaim(SysConstant.FIELD_ORG_NO,user.getOrgno())
//                .withClaim("loginName",user.getLoginname())
                .withClaim("macIp",user.getMacIp())
                .withClaim("userOrgInfoLevelInfo", userOrgInfoLevelInfo)
                .sign(Algorithm.HMAC256(user.getIscId()+ISSUER));//简单版  秘钥 用户id+发布人
//                .sign(Algorithm.HMAC256(user.getPassword()));//复杂版 工程项目使用
    }

    /**
     * 获取Token的接收者（业务上定义为IscUserEntity.iscid）
     * @param token
     * @return
     */
    public static String decodeGetAudience(String token) {
        if(StringUtils.isBlank(token)) {
            return null;
        }
        return JWT.decode(token).getAudience().get(0);
    }

    /**
     * 获取Token载荷中的String值
     * @param token
     * @param key
     * @return
     */
    public static String decodeGetStringValue(String token, String key) {
        if(StringUtils.isBlank(token)) {
            return "";
        }
        return JWT.decode(token).getClaim(key).asString();
    }

    /**
     * 解析Token的所有内容
     * @param token
     * @return
     */
    public static DecodeTokenInfoDTO getAllDecodeTokenInfo(String token){

        DecodeTokenInfoDTO dto = new DecodeTokenInfoDTO();
        if(StringUtils.isBlank(token)) {
            return null;
        }
        dto.setUserId(decodeGetAudience(token));
        dto.setUserName(decodeGetStringValue(token,"userName"));
        dto.setLoginName(decodeGetStringValue(token,"loginName"));
        HashMap<String, String> orgMap = decodeGetUserOrgInfoLevelInfo(token);
        orgMap.put("sszrq","100000");
        orgMap.put(SysConstant.FIELD_ORG_NO,decodeGetStringValue(token,SysConstant.FIELD_ORG_NO));
        dto.setUserOrgInfoLevelInfoMap(orgMap);
        return dto;
    }

    /**
     * 获取Token载荷中的用户拓展信息
     * @param token
     * @return
     */
    public static final HashMap<String,String> decodeGetUserOrgInfoLevelInfo(String token) {
        if(StringUtils.isBlank(token)) {
            return new HashMap<String ,String>();
        }
        HashMap<String,String> userOrgInfoLevelInfoMap = new HashMap<String ,String>();
        Map<String, Object> tempMap = JWT.decode(token).getClaim("userOrgInfoLevelInfo").asMap();
        for(String tempKey :tempMap.keySet()){
            userOrgInfoLevelInfoMap.put(tempKey,(String) tempMap.get(tempKey));
        }
        return userOrgInfoLevelInfoMap;
    }


    /**
     * 校验Token是否有效（自动获取秘钥）
     * @param token
     */
    public static boolean callVerifyToken(String token) {
        String secret = decodeGetStringValue(token,"userId") + ISSUER;
        return verifyToken(token,secret);
    }

    /**
     * 校验Token是否有效
     * @param token 令牌
     * @param secret 秘钥
     * @return
     */
    public static final boolean verifyToken(String token, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer(ISSUER)
                    .build();
            verifier.verify(token);
            return true;
        }catch(JWTVerificationException e) {
            log.warn("token校验失败，{}",e.getMessage());
            return false;
        }
    }

    /**
     * 校验Token是否过期
     * @param token
     * @return
     */
    public static final boolean isExpired(String token) {
        Long expireDate = getExpireDateFromToken(token);
        Long now = Calendar.getInstance().getTimeInMillis();
        //如果Token就会过期，则返回true
        if(expireDate - now <= 0) {
            return true;
        }
        return false;
    }

    /**
     * 获取token过期时间
     * @param token
     * @return
     */
    private static Long getExpireDateFromToken(String token) {
        try {
            DecodedJWT djwt = JWT.decode(token);
            Date expireDate = djwt.getExpiresAt();
            return expireDate.getTime();
        }catch(JWTDecodeException e) {
            log.warn("token不合法，解析失败，{}",token);
        }
        return Calendar.getInstance().getTimeInMillis();
    }
}
